/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:        sqbang                                                 *
 * Email:         sqbang@ustc.edu                                        *
 * Date:          2011.08.22                                             *
 *                                                                       *
 *************************************************************************/

#ifndef FreeMAPs_include_COMMON_equa_PDEEquationEnsembleStrategy_h
#define FreeMAPs_include_COMMON_equa_PDEEquationEnsembleStrategy_h

#include "FreeMAPsConfig.h"

//COMMON headers
#include "COMMON/equa/EquationEnsembleStrategy.h"


namespace FreeMAPs
{

//forward declarations
class SystemStrategy;
class ImplicitSystem;
class UnstructuredImplicitSystem;
class EquationDomain;
class InitializationCondition;
class IrregularBoundaryConditions;
class IrregularBoundaryConditionStrategy;
class PressureBoundaryCondition;
class DistributedLoadBoundaryCondition;
class ThermalStressLoadBoundaryCondition;
class Variable;
class Point;
class EquationSystems;
class CharactQuantity;
class RefinePatch;
/**
 * @brief PDEEquationEnsembleStrategy describes the differential equation ensemble to be solved.
 * An EquationEnsemble may consist by several equations, for examples:
 * \f[ \frac{df}{dt}=\nabla \cdot (f+g)\f]
 * \f[ \frac{dg}{dt}=\nabla \cdot (f-g)\f]
 * each equations will be described by an Equation.
 *
 * it is a derivated class of the following class:
 * -\li SAMRAI::mesh::TagAndInitializeStrategy
 *   to build mesh partially based on the information of the equation.
 * -\li SAMRAI::xfer::RefinePatchStrategy
 * -\li SAMRAI::xfer::CoarsenPatchStrategy
 *   to do data transfer between different level of patch.
 *
 * An equation ensemble's all equations will be solved by one system at same time
 * using same discrete scheme.
 * if two equations want to be solved by different scheme,
 * for example, one by FEM and one by FDM, then the best choice may be
 * build the two equations into two equation ensembles.
 *
 * @see Equation.h
 */
class PDEEquationEnsembleStrategy : public EquationEnsembleStrategy
{
public:

    virtual
    ~PDEEquationEnsembleStrategy();

public:

    inline bool
    do_write_character_quantity() const;

    inline IrregularBoundaryConditions*
    get_irregular_boundary_conditions() const;

    inline const std::map<std::string, InitializationCondition*> &
    get_init_conditions()const;


public:
    /**
     * used for deconstructor function.
     * to clear all pointer created by this class.
     */
    virtual void
    clear();

    virtual void
    get_from_input (
        const InputDatabase* db);

    friend std::ostream&
    operator << (
        std::ostream& os,
        const PDEEquationEnsembleStrategy& rhs);

    bool
    check_all_info_db(
            const std::string equation_ensemble_name,
            const InputDatabase* db);

    /**
      * get a concrete instance for the class corresponding to the type.
      */
     static PDEEquationEnsembleStrategy*
     create_object (
         const EquationEnsembleType eq_type,
         const std::string& parent_name,
         const std::string& object_name/*,
         const int sys_id*/);

     bool
     use_structured_mesh() const;

     virtual EquationEnsembleType
     get_equation_ensemble_type() const = 0;

     //add initialize_conditions
     void
     add_initialize_condition(
             const std::string ic_name,
             const double init_value);

     //domain
     void
     set_domain_region_name(
             const std::string domain_region_name);

     const std::string&
     get_domain_region_name() const;

     // system
     SystemStrategy*
     get_system_strategy();

protected:
     virtual void
     get_info_for_derived_object_from_input (
         const InputDatabase* db) = 0;

     virtual std::string
     get_info_from_derived_object() const = 0;


protected:
     /*
      * constructor function
      */
     explicit
     PDEEquationEnsembleStrategy (
         const std::string& parent_name,
         const std::string& object_name/*,
         const int sys_id*/);

    typedef EquationEnsembleStrategy Parent;

    //SystemStrategy* d_system;
    //int d_sys_id;

    bool d_do_write_character_quantity;

    EquationDomain* d_equation_domain;

    // system
    SystemStrategy* d_system;

    /*
     * the boundary conditions applied on the level set's boundary
     * (where phi(x)=0)
     */
    IrregularBoundaryConditions* d_irregular_bdry_conds;

    /*
     * map<ic_name, ic>
     */
    std::map<std::string, InitializationCondition*> d_init_conditions;

private:
    EquationEnsembleType d_equation_ensemble_type;


private:

    DISALLOW_COPY_AND_ASSIGN (PDEEquationEnsembleStrategy);

};

} // namespace FreeMAPs

#include "COMMON/equa/PDEEquationEnsembleStrategy.inl"

#endif
